import { log } from "../../utils/log";
import { EventDispatcher } from "../event/EventDispatcher";

export type PeerBaseEvent = {
    iceConnectionClosed: { target: Peer; };
    iceConnectionFailed: { target: Peer; };
    iceConnectionDisconnected: { target: Peer; };
    iceConnectionChanged: { target: Peer; };
    iceConnectionChecking: { target: Peer; };
    iceConnectionCompleted: { target: Peer; };
    iceConnectionConnected: { target: Peer; };
    iceConnectionNew: { target: Peer; };
};

export class Peer<T extends PeerBaseEvent = PeerBaseEvent> extends EventDispatcher<T & PeerBaseEvent> {

    peerConnection: RTCPeerConnection;

    hostName: string = window.location.hostname;

    constructor() {

        super();

        // Create an RTCPeerConnection which knows to use our chosen
        // STUN server.

        this.peerConnection = new RTCPeerConnection({
            iceServers: [     // Information about ICE servers - Use your own!
                {
                    urls: "turn:" + this.hostName,  // A TURN server
                    username: "webrtc",
                    credential: "turnserver"
                }
            ]
        });

        // Set up event handlers for the ICE negotiation process.

        this.peerConnection.onicecandidate = this.handleICECandidateEvent;
        this.peerConnection.oniceconnectionstatechange = this.handleICEConnectionStateChangeEvent;
        this.peerConnection.onicegatheringstatechange = this.handleICEGatheringStateChangeEvent;
        this.peerConnection.onsignalingstatechange = this.handleSignalingStateChangeEvent;
        this.peerConnection.onnegotiationneeded = handleNegotiationNeededEvent;
        this.peerConnection.ontrack = handleTrackEvent;

    }

    handleICECandidateEvent(event: RTCPeerConnectionIceEvent) {
        if (event.candidate) {
            log("*** Outgoing ICE candidate: " + event.candidate.candidate);

            // sendToServer({
            //     type: "new-ice-candidate",
            //     target: targetUsername,
            //     candidate: event.candidate
            // });
        }
    }

    // Handle |iceconnectionstatechange| events. This will detect
    // when the ICE connection is closed, failed, or disconnected.
    //
    // This is called when the state of the ICE agent changes.

    handleICEConnectionStateChangeEvent() {

        log("*** ICE connection state changed to " + this.peerConnection.iceConnectionState);

        this.dispatchEvent({ type: "iceConnectionChanged", target: this });

        switch (this.peerConnection.iceConnectionState) {
            case "closed":
                this.dispatchEvent({ type: "iceConnectionClosed", target: this });
                break;
            case "failed":
                this.dispatchEvent({ type: "iceConnectionFailed", target: this });
                break;
            case "disconnected":
                this.dispatchEvent({ type: "iceConnectionDisconnected", target: this });
                break;
            case "checking":
                this.dispatchEvent({ type: "iceConnectionChecking", target: this });
                break;
            case "completed":
                this.dispatchEvent({ type: "iceConnectionCompleted", target: this });
                break;
            case "connected":
                this.dispatchEvent({ type: "iceConnectionConnected", target: this });
                break;
            case "new":
                this.dispatchEvent({ type: "iceConnectionNew", target: this });
                break;
        }

    }

    // Handle the |icegatheringstatechange| event. This lets us know what the
    // ICE engine is currently working on: "new" means no networking has happened
    // yet, "gathering" means the ICE engine is currently gathering candidates,
    // and "complete" means gathering is complete. Note that the engine can
    // alternate between "gathering" and "complete" repeatedly as needs and
    // circumstances change.
    //
    // We don't need to do anything when this happens, but we log it to the
    // console so you can see what's going on when playing with the sample.

    handleICEGatheringStateChangeEvent(event: Event) {
        log("*** ICE gathering state changed to: " + this.peerConnection.iceGatheringState);
    }


    // Set up a |signalingstatechange| event handler. This will detect when
    // the signaling connection is closed.
    //
    // NOTE: This will actually move to the new RTCPeerConnectionState enum
    // returned in the property RTCPeerConnection.connectionState when
    // browsers catch up with the latest version of the specification!

    handleSignalingStateChangeEvent() {
        log("*** WebRTC signaling state changed to: " + this.peerConnection.signalingState);
        switch (this.peerConnection.signalingState) {
            case "closed":
                closeVideoCall();
                break;
        }
    }

}